define(["dojo/_base/declare", "esri/layers/layer", "dojo/_base/config", "dojo/dom-construct", "esri/geometry/Point",
        "dojo/on"
    ],
    function(declare, Layer, config, domConstruct, Point, on) {
        return declare([Layer], {
            constructor: function(p) {
                dojo.safeMixin(this, p);
                this.loaded = true;
                this.onLoad(this);
            },
            _setMap: function(map, container) {
                this.map = map;
                this.canvas = domConstruct.create("canvas", {
                    id: "canvas",
                    width: map.width + "px",
                    height: map.height + "px",
                    style: "position: absolute; left: 0px; top: 0px;"
                }, container);
                this.layersElement = container;

                this.removeHandle();

                this._panStartHandle = map.on('pan-start', () => {
                    this.canvas.style.display = 'none';
                });
                this._zoomStartHandle = map.on('zoom-start', () => {
                    this.canvas.style.display = 'none';
                });
                this._extentChangeHandle = map.on("extent-change", () => {
                    this._refresh();
                });
                return this.canvas;
            },
            _unsetMap: function(map, container) {
                if (this.canvas) {
                    container.removeChild(this.canvas);
                };
                this.canvas = null;
                this.removeHandle();

            },
            removeHandle: function() {
                if (this._extentChangeHandle) {
                    this._extentChangeHandle.remove();
                    this._extentChangeHandle = null;
                };
                if (this._panStartHandle) {
                    this._panStartHandle.remove();
                    this._panStartHandle = null;
                };
                if (this._zoomStartHandle) {
                    this._zoomStartHandle.remove();
                    this._zoomStartHandle = null;
                };
            },
            clear: function() {
                this.data = [];
                this.inherited(arguments);
            },
            canvas: null,
            clear: function(context) {
                context && context.clearRect && context.clearRect(0, 0, context.canvas.width, context.canvas.height);
            },
            init: function() {
                var me = this;
                this.context = this.context || '2d';
                if (this.canvas && this.mapv) {
                    var ctx = this.canvas.getContext(this.context);
                    this.ctx = ctx;
                    var DataSet = this.mapv.DataSet;
                    var data = this.data;
                    var dataSet = new DataSet(data);
                    this.dataSet = dataSet;
                    this.initDataRange(this.options);
                    if (this.options.zIndex) {
                        this.canvasLayer && this.canvasLayer.setZIndex(this.options.zIndex);
                    }

                    if (this.options.max) {
                        this.intensity.setMax(this.options.max);
                    }

                    if (this.options.min) {
                        this.intensity.setMin(this.options.min);
                    }

                    me.initAnimator();
                    me._refresh();
                }
            },
            initDataRange: function(options) {
                var self = this;
                var mapv = this.mapv;
                if (!self.options) {
                    return;
                }
                self.intensity = new mapv.utilDataRangeIntensity({
                    maxSize: self.options.maxSize,
                    minSize: self.options.minSize,
                    gradient: self.options.gradient,
                    max: self.options.max || this.dataSet.getMax('count')
                });
                self.category = new mapv.utilDataRangeCategory(self.options.splitList);
                self.choropleth = new mapv.utilDataRangeChoropleth(self.options.splitList);
                if (self.options.splitList === undefined) {
                    self.category.generateByDataSet(this.dataSet, self.options.color);
                }
                if (self.options.splitList === undefined) {
                    var min = self.options.min || this.dataSet.getMin('count');
                    var max = self.options.max || this.dataSet.getMax('count');
                    self.choropleth.generateByMinMax(min, max);
                };
            },
            initAnimator: function() {
                var self = this;
                var animationOptions = self.options.animation;

                if (self.options.draw == 'time' || self.isEnabledTime()) {

                    if (!animationOptions.stepsRange) {
                        animationOptions.stepsRange = {
                            start: this.dataSet.getMin('time') || 0,
                            end: this.dataSet.getMax('time') || 0
                        };
                    }

                    this.steps = { step: animationOptions.stepsRange.start };
                    self.animator = new this.mapv.TWEEN.Tween(this.steps).onUpdate(function() {
                        self._canvasUpdate(this.step);
                    }).repeat(Infinity);

                    this.addAnimatorEvent();

                    var duration = animationOptions.duration * 1000 || 5000;

                    self.animator.to({ step: animationOptions.stepsRange.end }, duration);
                    self.animator.start();
                } else {
                    self.animator && self.animator.stop();
                }
            },
            addAnimatorEvent: function() {},
            _refresh: function() {
                if (!this.visible) {
                    return;
                };
                if (this.canvas && this.mapv) {
                    if (this.map) {
                        this.setScale(this.map, this.canvas);
                    };
                    if (!this._elementVisible) {
                        return;
                    };
                    this.canvas.width = this.map.width;
                    this.canvas.height = this.map.height;
                    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                    this.canvasResolutionScale(this.ctx);
                    this._canvasUpdate();
                };
            },
            transferCoordinate: function(coordinate) {
                var map = this.map;
                if (!map) {
                    console.log('缺少map!');
                    return;
                }
                var point = new Point(coordinate[0], coordinate[1], map.spatialReference);
                var pixel = map.toScreen(point);
                return [pixel.x, pixel.y];
            },
            _canvasUpdate: function(time) {
                var self = this;

                var animationOptions = self.options.animation;

                var map = this.map;

                var zoomUnit = Math.pow(2, 18 - map.getZoom());

                var context = this.ctx;

                if (self.isEnabledTime()) {
                    if (time === undefined) {
                        self.clear(context);
                        return;
                    }
                    if (this.context == '2d') {
                        context.save();
                        context.globalCompositeOperation = 'destination-out';
                        context.fillStyle = 'rgba(0, 0, 0, .1)';
                        context.fillRect(0, 0, context.canvas.width, context.canvas.height);
                        context.restore();
                    }
                } else {
                    self.mapv.canvasClear(context);
                }

                if (this.context == '2d') {
                    for (var key in self.options) {
                        context[key] = self.options[key];
                    }
                } else {
                    context.clear(context.COLOR_BUFFER_BIT);
                }

                if (self.options.minZoom && map.getZoom() < self.options.minZoom || self.options.maxZoom && map.getZoom() > self.options.maxZoom) {
                    return;
                }

                var scale = 1;
                if (this.context != '2d') {
                    scale = this.devicePixelRatio;
                }

                var dataGetOptions = {
                    transferCoordinate: this.transferCoordinate
                };

                if (time !== undefined) {
                    dataGetOptions.filter = function(item) {
                        var trails = animationOptions.trails || 10;
                        if (time && item.time > time - trails && item.time < time) {
                            return true;
                        } else {
                            return false;
                        }
                    };
                }

                var data = self.dataSet.get(dataGetOptions);

                if (self.options.unit == 'm') {
                    if (self.options.size) {
                        self.options._size = self.options.size / zoomUnit;
                    }
                    if (self.options.width) {
                        self.options._width = self.options.width / zoomUnit;
                    }
                    if (self.options.height) {
                        self.options._height = self.options.height / zoomUnit;
                    }
                } else {
                    self.options._size = self.options.size;
                    self.options._height = self.options.height;
                    self.options._width = self.options.width;
                }

                this.drawContext(context, data, self.options);

                self.options.updateCallback && self.options.updateCallback(time);
            },
            drawContext: function(context, dataSet, options) {
                var self = this;
                switch (self.options.draw) {
                    case 'heatmap':
                        drawHeatmap.draw(context, dataSet, self.options);
                        break;
                    case 'text':
                        drawText.draw(context, dataSet, self.options);
                        break;
                    case 'icon':
                        drawIcon.draw(context, dataSet, self.options);
                        break;
                    case 'clip':
                        drawClip.draw(context, dataSet, self.options);
                        break;
                    default:
                        if (self.options.context == "webgl") {
                            webglDrawSimple.draw(self.canvasLayer.canvas.getContext('webgl'), dataSet, self.options);
                        } else {
                            this.mapv.canvasDrawSimple.draw(context, dataSet, self.options);
                        }
                };

                if (self.options.arrow && self.options.arrow.show !== false) {
                    object.draw(context, dataSet, self.options);
                };
            },
            isEnabledTime: function() {

                var animationOptions = this.options.animation;

                var flag = animationOptions && !(animationOptions.enabled === false);

                return flag;
            },
            canvasResolutionScale: function(context) {
                var devicePixelRatio = this.devicePixelRatio;
                context.canvas.width = context.canvas.width * devicePixelRatio;
                context.canvas.height = context.canvas.height * devicePixelRatio;
                context.canvas.style.width = context.canvas.width / devicePixelRatio + 'px';
                context.canvas.style.height = context.canvas.height / devicePixelRatio + 'px';
                context.scale(devicePixelRatio, devicePixelRatio);
            },
            visible: true,
            _elementVisible: true,
            setVisibility: function(visible) {
                this.visible = visible;
                if (this.canvas) {
                    if (visible) {
                        this.refresh();
                        this.canvas.style.display = "block";
                    } else
                        this.canvas.style.display = "none";
                }
            },
            removeLayer: function() {
                this.removeHandle();
                if (this.canvas) {
                    this.canvas.parentNode.removeChild(this.canvas);
                }

                if (this._legendElement) {
                    this._legendElement.parentNode.removeChild(this._legendElement);
                    this._legendElement = null;
                };
            },
            /*修改色带的透明度，给图例用的色带不用加透明度*/
            modifyGradient: function(gradient) {
                this.legendGradient = gradient;
                for (var i in gradient) {
                    var item = gradient[i].toLowerCase();
                    if (item.includes('rgba')) {
                        item = item.slice(5, -1).split(",");
                        item.pop();
                        item = 'rgb(' + item.join(',') + ')';
                        this.legendGradient[i] = item;
                    };
                }
            },
            getLegend: function(options = { style: {} }) {
                this.modifyGradient(Object.assign(this.gradient));
                var gradient = this.legendGradient || this.gradient;
                var canvasHeight = parseInt(options.canvasHeight) || 120;
                var canvasWidth = parseInt(options.canvasWidth) || 20;
                this._legendElement = domConstruct.create("div", {
                    style: Object.assign(options.style),
                    class: ['layerLegend']
                }, this.layersElement);
                var titleElement = domConstruct.create("div", {
                    style: {
                        'text-align': 'center',
                        'font-size': '16px',
                        'font-weight': 'bold'
                    }
                }, this._legendElement);
                titleElement.innerHTML = `<div style="padding-bottom:5px;">图&nbsp&nbsp例</div>`;

                var contentElement = domConstruct.create("div", { style: { position: "relative" } }, this._legendElement);
                contentElement.innerHTML = `<div style="position:absolute;top: -2px;right: 0px;">最大值</div>
                                      <div style="position:absolute;top: ${canvasHeight - 16}px;right: 0px;">最小值</div>
                                     `;
                var _contentWidth = $(contentElement).width() || 42;

                var canvas = domConstruct.create("canvas", {
                    width: canvasWidth + _contentWidth + 'px',
                    height: canvasHeight + 'px'
                }, contentElement);

                var paletteCtx = canvas.getContext('2d');

                var lineGradient = paletteCtx.createLinearGradient(0, canvasHeight, 0, 0);

                for (var key in gradient) {
                    lineGradient.addColorStop(parseFloat(key), gradient[key]);
                }

                paletteCtx.fillStyle = lineGradient;
                paletteCtx.fillRect(0, 0, canvasWidth, canvasHeight);

                return canvas;
            },
            hideLayer: function() {
                this.visible = false;
                this._elementVisible = false;
                this.canvas.style.display = 'none';
            },
            showLayer: function() {
                this.visible = true;
                this._elementVisible = true;
                this.canvas.style.display = 'block';
                this._refresh();
            },
            setScale: function(map, _element) {
                var scale = map.getScale();

                if (this.options && this.options.minScale && this.options.maxScale) {
                    if (scale > this.options.minScale || scale < this.options.maxScale) {
                        _element.style.display = 'none';
                        this._elementVisible = false;
                    } else {
                        _element.style.display = 'block';
                        this._elementVisible = true;
                    };
                } else if (this.options && this.options.minScale > 0) {
                    if (scale > this.options.minScale) {
                        _element.style.display = 'none';
                        this._elementVisible = false;
                    } else {
                        _element.style.display = 'block';
                        this._elementVisible = true;
                    };
                } else if (this.options && this.options.maxScale > 0) {
                    if (scale < this.options.maxScale) {
                        _element.style.display = 'none';
                        this._elementVisible = false;
                    } else {
                        _element.style.display = 'block';
                        this._elementVisible = true;
                    };
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                };
            },
            convertSr: function(mapView, lngLatArray, callback) {
                var me = this;
                if (!mapView) {
                    return;
                };
                var mapUtils = mapView.mapUtils;
                var mapSr = mapView.getSpatialReference();
                me.mapSr = mapSr;
                var layerSr = me.spatialReference;
                if (mapSr == layerSr) {
                    callback();
                    return
                };
                /*坐标转换，扩展的图层不像svg可以自动转换坐标，如果点位的坐标与底图的坐标不一致需要先手工转换坐标*/
                if (mapSr.wkid == '102100') {
                    if (layerSr.wkid == '4326' || layerSr.wkid == '4490') {
                        me.lngLatToXY(mapView, mapUtils, lngLatArray, function(lngLatArray) {
                            if ($.isFunction(callback)) {
                                callback(lngLatArray, mapSr);
                            };
                        });
                        return;
                    };
                };
                if (mapSr.wkid == '4326' || mapSr.wkid == '4490') {
                    if (layerSr.wkid == '102100') {
                        me.xyToLngLat(mapView, mapUtils, lngLatArray, function(lngLatArray) {
                            if ($.isFunction(callback)) {
                                callback(lngLatArray, mapSr);
                            };
                        });
                        return;
                    };

                };
                if ($.isFunction(callback)) {
                    callback(lngLatArray, me.spatialReference);
                };

            },
            lngLatToXY: function(mapView, mapUtils, lngLatArray, callback) {
                mapUtils.webMercatorUtils(mapView, lngLatArray, { isLngLat: true, callback: callback });
            },
            xyToLngLat: function(mapView, mapUtils, data, callback) {
                mapUtils.webMercatorUtils(mapView, lngLatArray, { isLngLat: false, callback: callback });
            }

        });
    });